/*
 *  Copyright 2012 Dirk Vranckaert
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package eu.vranckaert.vvl.utils.context;

import static eu.vranckaert.vvl.testutil.MyAssert.assertContains;
import static eu.vranckaert.vvl.testutil.MyAssert.assertNotContains;
import android.content.Context;
import android.test.AndroidTestCase;
import eu.vranckaert.vvl.model.TrafficInfoAlarm;
import eu.vranckaert.vvl.model.TrafficInfoGraphicalEnum;
import eu.vranckaert.vvl.model.TrafficInfoTextEnum;
import eu.vranckaert.vvl.model.TypeTrafficInfoEnum;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;

/**
 * User: DIRK VRANCKAERT
 * Date: 23/02/12
 * Time: 7:52
 */
public class PreferenceTest extends AndroidTestCase {
    private Context ctx;

    @Override
    protected void setUp() throws Exception {
        super.setUp();
        ctx = getContext();
    }

    public void testSelectedTextInformationTypes() {
        Preference.removePreference(ctx, Constants.Preferences.Keys.SELECTED_TEXT_INFORMATION_TYPES);

        int expectedNumberOfInformationTypesFound = TrafficInfoTextEnum.InformationType.values().length;
        List<TrafficInfoTextEnum.InformationType> informationTypes = Preference.getSelectedTextInformationTypes(ctx);
        assertEquals(expectedNumberOfInformationTypesFound + " types are expected to be found!", expectedNumberOfInformationTypesFound, informationTypes.size());

        TrafficInfoTextEnum.InformationType[] typesToSet = {TrafficInfoTextEnum.InformationType.TRAFFIC_INFO, TrafficInfoTextEnum.InformationType.ACCIDENTS};
        Preference.setSelectedTextInformationTypes(ctx, Arrays.asList(typesToSet));
        expectedNumberOfInformationTypesFound = typesToSet.length;
        informationTypes = Preference.getSelectedTextInformationTypes(ctx);
        assertEquals(expectedNumberOfInformationTypesFound + " types are expected to be found!", expectedNumberOfInformationTypesFound, informationTypes.size());

        Preference.removePreference(ctx, Constants.Preferences.Keys.SELECTED_TEXT_INFORMATION_TYPES);
    }

    public void testSelectedTextRegions() {
        Preference.removePreference(ctx, Constants.Preferences.Keys.SELECTED_TEXT_REGIONS);

        int expectedNumberOfRegionsFound = TrafficInfoTextEnum.Region.values().length;
        List<TrafficInfoTextEnum.Region> regions = Preference.getSelectedTextRegions(ctx);
        assertEquals(expectedNumberOfRegionsFound + " regions are expected to be found!", expectedNumberOfRegionsFound, regions.size());

        TrafficInfoTextEnum.Region[] regionsToSet = {TrafficInfoTextEnum.Region.BRUSSEL, TrafficInfoTextEnum.Region.KEMPEN, TrafficInfoTextEnum.Region.LIMBURG};
        Preference.setSelectedTextRegions(ctx, Arrays.asList(regionsToSet));
        expectedNumberOfRegionsFound = regionsToSet.length;
        regions = Preference.getSelectedTextRegions(ctx);
        assertEquals(expectedNumberOfRegionsFound + " regions are expected to be found!", expectedNumberOfRegionsFound, regions.size());

        Preference.removePreference(ctx, Constants.Preferences.Keys.SELECTED_TEXT_REGIONS);
    }
    
    public void testSelectedGraphicalRegion() {
        Preference.removePreference(ctx, Constants.Preferences.Keys.SELECTED_GRAPHICAL_REGION);

        TrafficInfoGraphicalEnum.Region defaultRegion = TrafficInfoGraphicalEnum.Region.getByValue(Constants.Preferences.DefaultValues.SELECTED_GRAPHICAL_REGION);
        TrafficInfoGraphicalEnum.Region selectedRegion = Preference.getSelectedGraphicalRegion(ctx);
        assertNotNull("The selected region should not be null!", selectedRegion);
        assertEquals(defaultRegion, selectedRegion);

        TrafficInfoGraphicalEnum.Region regionToSet = TrafficInfoGraphicalEnum.Region.GHENT;
        assertTrue("The region that will be set is not expected to be the same as the default one!", !regionToSet.equals(defaultRegion));
        Preference.setSelectedGraphicalRegion(ctx, regionToSet);
        selectedRegion = Preference.getSelectedGraphicalRegion(ctx);
        assertNotNull("The selected region should not be null!", selectedRegion);
        assertEquals(regionToSet, selectedRegion);
        
        Preference.removePreference(ctx, Constants.Preferences.Keys.SELECTED_GRAPHICAL_REGION);
    }
    
    public void testNextAlarmRequestCode() {
        Preference.removePreference(ctx, Constants.Preferences.Keys.ALARM_REQUEST_CODE);
        
        int expectedResult = Constants.Preferences.DefaultValues.ALARM_REQUEST_CODE + 1;
        int result = Preference.getNextAlarmRequestCode(ctx);
        assertEquals("The default value is expected", expectedResult, result);
        
        expectedResult++;
        result = Preference.getNextAlarmRequestCode(ctx);
        assertEquals("The default value + 1 is expected!", expectedResult, result);
    }
    
    public void testAlarms() {
        Preference.removePreference(ctx, Constants.Preferences.Keys.SAVED_ALARMS);
        Preference.removePreference(ctx, Constants.Preferences.Keys.ALARM_REQUEST_CODE);

        int numberOfAlarms = 3;
        // First is single shot, second is repeating 3 days, third is repeating monday
        List<TrafficInfoAlarm> alarms = buildTrafficInfoAlarms(numberOfAlarms);

        // getAlarms(..)
        int expectedNumberOfResult = 0;
        List<TrafficInfoAlarm> results = Preference.getAlarms(ctx);
        assertEquals("Number of expected results: " + expectedNumberOfResult, expectedNumberOfResult, results.size());

        // addAlarm(..)
        expectedNumberOfResult = 1;
        TrafficInfoAlarm alarmToAdd = alarms.get(0);
        Preference.addAlarm(ctx, alarmToAdd);
        results = Preference.getAlarms(ctx);
        assertEquals("Number of expected results: " + expectedNumberOfResult, expectedNumberOfResult, results.size());
        assertContains("The alarm should be in the list!", alarmToAdd, results);
        assertFalse("This is not a repeating alarm", alarms.get(0).isRepeatingAlarm());

        // addAlarm(..)
        expectedNumberOfResult = 3;
        Preference.addAlarm(ctx, alarms.get(1));
        Preference.addAlarm(ctx, alarms.get(2));
        results = Preference.getAlarms(ctx);
        assertEquals("Number of expected results: " + expectedNumberOfResult, expectedNumberOfResult, results.size());
        assertContains("The alarm should be in the list!", alarms.get(0), results);
        assertContains("The alarm should be in the list!", alarms.get(1), results);
        assertContains("The alarm should be in the list!", alarms.get(2), results);
        assertFalse("This should not be a repeating alarm", alarms.get(0).isRepeatingAlarm());
        assertTrue("This should be a repeating alarm", alarms.get(1).isRepeatingAlarm());
        assertTrue("This should be a repeating alarm", alarms.get(2).isRepeatingAlarm());

        // deleteAlarm(..)
        expectedNumberOfResult = 2;
        Preference.deleteAlarm(ctx, alarms.get(0));
        results = Preference.getAlarms(ctx);
        assertEquals("Number of expected results: " + expectedNumberOfResult, expectedNumberOfResult, results.size());
        assertNotContains("The alarm should not be in the list!", alarms.get(0), results);

        // getAlarm(..) with passed single-shot alarm!
        alarmToAdd = alarms.get(0);
        // Make sure the alarm time of a single shot alarm is in the past
        Calendar alarmTimeInPast = Calendar.getInstance();
        alarmTimeInPast.set(Calendar.YEAR, 2000);
        alarmToAdd.setAlarmTime(alarmTimeInPast);
        expectedNumberOfResult = 2;
        results = Preference.getAlarms(ctx);
        assertEquals("Number of expected results: " + expectedNumberOfResult, expectedNumberOfResult, results.size());
        Preference.addAlarm(ctx, alarmToAdd);
        results = Preference.getAlarms(ctx);
        assertEquals("Number of expected results should still be " + expectedNumberOfResult, expectedNumberOfResult, results.size());
        alarmToAdd = alarms.get(1);
        Preference.deleteAlarm(ctx, alarmToAdd);
        expectedNumberOfResult = 1;
        results = Preference.getAlarms(ctx);
        assertEquals("Number of expected results: " + expectedNumberOfResult, expectedNumberOfResult, results.size());
        alarmToAdd.setAlarmTime(alarmTimeInPast);
        Preference.addAlarm(ctx, alarmToAdd);
        expectedNumberOfResult = 2;
        results = Preference.getAlarms(ctx);
        assertEquals("Number of expected results should be increased to: " + expectedNumberOfResult, expectedNumberOfResult, results.size());
    }

    private List<TrafficInfoAlarm> buildTrafficInfoAlarms(int numberOfAlarms) {
        List<TrafficInfoAlarm> alarms = new ArrayList<TrafficInfoAlarm>();
        
        for (int i=0; i<numberOfAlarms; i++) {
            TrafficInfoAlarm alarm = new TrafficInfoAlarm();

            Calendar cal = Calendar.getInstance();
            cal.set(Calendar.HOUR_OF_DAY, i);
            cal.set(Calendar.MINUTE, 25 + i);

            if (i == 0) {
                // Single shot alarm
                cal.add(Calendar.HOUR_OF_DAY, 24); //Make it one day in the future..
                alarm.setAlarmTime(cal);
                alarm.setAlarmIds(Arrays.asList(new Integer[]{Preference.getNextAlarmRequestCode(ctx)}));
                
                alarm.setRepeatingDays(new ArrayList<Constants.WeekDays>());
                
                alarm.setTypeTrafficInfo(TypeTrafficInfoEnum.TEXT);
                alarm.setTextInfoTypes(new ArrayList<TrafficInfoTextEnum.InformationType>(
                        Arrays.asList(new TrafficInfoTextEnum.InformationType[]{
                                TrafficInfoTextEnum.InformationType.TRAFFIC_INFO,
                                TrafficInfoTextEnum.InformationType.TRAFFIC_JAMS
                        }))
                );
                alarm.setTextRegions(new ArrayList<TrafficInfoTextEnum.Region>(
                        Arrays.asList(new TrafficInfoTextEnum.Region[]{
                                TrafficInfoTextEnum.Region.BRUSSEL,
                                TrafficInfoTextEnum.Region.GENT
                        }))
                );
                alarm.setTextHighroads(new ArrayList<TrafficInfoTextEnum.Highroad>());
                alarm.setTextSecondaryRoads(new ArrayList<TrafficInfoTextEnum.SecondaryRoads>());
            } else {
                if (i == 1) {
                    // Repeating alarm on Monday, Tuesday and Friday
                    alarm.setAlarmTime(cal);
                    alarm.setAlarmIds(Arrays.asList(new Integer[]{Preference.getNextAlarmRequestCode(ctx),
                            Preference.getNextAlarmRequestCode(ctx), Preference.getNextAlarmRequestCode(ctx)}));

                    alarm.setRepeatingDays(Arrays.asList(new Constants.WeekDays[]{Constants.WeekDays.MONDAY,
                            Constants.WeekDays.TUESDAY, Constants.WeekDays.FRIDAY}));
                } else {
                    // Repeating alarm on Monday
                    alarm.setAlarmTime(cal);
                    alarm.setAlarmIds(Arrays.asList(new Integer[]{Preference.getNextAlarmRequestCode(ctx)}));

                    alarm.setRepeatingDays(Arrays.asList(new Constants.WeekDays[]{Constants.WeekDays.MONDAY}));
                }
                
                alarm.setTypeTrafficInfo(TypeTrafficInfoEnum.GRAPHICAL);
                alarm.setGraphicalRegion(TrafficInfoGraphicalEnum.Region.GHENT);
            }
            
            alarms.add(alarm);
        }

        return alarms;
    }
}
